package com.sinodata.bsm.center.expression;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.log4j.Logger;

import com.sinodata.bsm.center.bean.AttributeBean;
import com.sinodata.bsm.center.bean.PropValueBean;
import com.sinodata.bsm.center.bean.PropertyBean;
import com.sinodata.bsm.center.bean.RelationHelper;
import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.bean.ResTypeBean;
import com.sinodata.bsm.center.cache.NewEventCache;
import com.sinodata.bsm.center.cache.PropertyValueCache;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.DataTypeConstants;
import com.sinodata.bsm.common.constants.SeparatorConstants;
import com.sinodata.bsm.common.vo.Attribute;
import com.sinodata.bsm.common.vo.Property;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResAttrVal;

/**
 * @author tangli
 * 
 */
public class Functions {

    private static PropertyValueCache propertyValueCache = SpringContextHolder.getBean(PropertyValueCache.class);

    private static NewEventCache newEventCache = SpringContextHolder.getBean(NewEventCache.class);

    protected static Logger logger = Logger.getLogger(Functions.class);

    /**
     * 获取特定类别的子孙资源 (为了性能暂时最深找3层)
     * 
     * @param resId
     *            resTypeId
     * @return
     */
    public static List<ResBean> descentsByType(Long resId, Long resTypeId) {
        return ResBean.get(resId).descentsByType(resTypeId, 3);
    }

    public static List<Res> childByProp(Long resId, Long propId) {
        List<Res> ret = new ArrayList<Res>();
        ResBean res = ResBean.get(resId);
        List<ResBean> children = res.descents(3);
        children.add(res);
        for (ResBean child : children) {
            if (isContainProp(child.res().getId(), propId)) {
                ret.add(child.res());
            }
        }
        return ret;
    }

    /**
     * 获取一个资源
     * 
     * @param resId
     * @return
     */
    public static Object res(Long resId) {
        return ResBean.get(resId);
    }

    /**
     * 获得某个类别的全部子资源
     * 
     * @param resId
     * @param resTypeId
     * @return
     */
    public static Object children(Long resId, Long resTypeId) {
        ResBean res = ResBean.get(resId);
        return res.childrenByType(resTypeId);
    }

    /**
     * 获取第一个子孙资源类别的指标值
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object childProp(Long resId, Long propId) {
        ResBean res = ResBean.get(resId);
        if (isContainProp(resId, propId)) {
            return getPropertyValue(resId, propId);
        }
        List<ResBean> childs = res.descents(3);
        for (ResBean child : childs) {
            if (isContainProp(child.res().getId(), propId)) {
                return getPropertyValue(child.res().getId(), propId);
            }
        }
        return null;
    }

    /**
     * 获取子类别指标累加值
     * 
     * @param resId
     * @param propId
     * @return
     * @throws Exception
     */
    public static Object sumChildProp(Long resId, Long propId) throws Exception {
        ResBean res = ResBean.get(resId);
        PropertyBean propBean = PropertyBean.get(propId);
        if (propBean.property().getDataTypeId().intValue() != DataTypeConstants.DATA_TYPE_NUM) {
            throw new Exception("porpId=[" + propId + "] 不是数字类型，不能比较大小");
        }
        if (isContainProp(resId, propId)) {
            return getPropertyValue(resId, propId);
        }
        List<ResBean> childs = res.descents(3);
        float ret = 0;
        for (ResBean child : childs) {
            if (isContainProp(child.res().getId(), propId)) {
                return ret += getFloatProp(child.res().getId(), propId);
            }
        }
        return ret;
    }

    /**
     * 获取第一个子孙资源类别的属性值
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object childAttr(Long resId, Long attrId) {
        ResBean res = ResBean.get(resId);
        if (isContainAttr(resId, attrId)) {
            return getAttributeValue(resId, attrId);
        }
        List<ResBean> childs = res.descents(3);
        for (ResBean child : childs) {
            if (isContainAttr(child.res().getId(), attrId)) {
                return getAttributeValue(child.res().getId(), attrId);
            }
        }
        return null;
    }

    private static boolean isContainAttr(long resId, long attrId) {
        ResBean res = ResBean.get(resId);
        ResTypeBean resType = ResTypeBean.get(res.res().getResTypeId());
        for (Attribute attr : resType.attributes()) {
            if (attr.getId().longValue() == attrId) {
                return true;
            }
        }
        return false;
    }

    private static boolean isContainProp(long resId, long propId) {
        ResBean res = ResBean.get(resId);
        ResTypeBean resType = ResTypeBean.get(res.res().getResTypeId());
        for (Property prop : resType.properties()) {
            if (prop.getId().longValue() == propId) {
                return true;
            }
        }
        return false;
    }

    /**
     * 1.致命（红） ：#ce110f 2.严重（深黄）：#ff9937 3.警告（浅黄）：#dede03 4.次要（蓝色）：#0c7ce5
     * 5.未知（灰色）：#969c92
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object eventColor(Long resId, Long propId) {
        int level = newEventCache.getNewEventsMaxLevel(resId, new Long[] { propId });
        int ret = 0;
        switch (level) {
            case 1:
                ret = 0xff00;
                break;
            case 2:
                ret = 0x0c7ce5;
                break;
            case 3:
                ret = 0xdede03;
                break;
            case 4:
                ret = 0xff9937;
                break;
            case 5:
                ret = 0xce110f;
                break;
            default:
                ret = 0xff00;
        }
        return ret;
    }

    /**
     * 
     * @param resId
     * @param propId
     * @return
     * @throws Exception
     */
    public static Res maxChild(Long resId, Long propId) throws Exception {
        PropertyBean propBean = PropertyBean.get(propId);
        if (propBean.property().getDataTypeId().intValue() != DataTypeConstants.DATA_TYPE_NUM) {
            throw new Exception("porpId=[" + propId + "] 不是数字类型，不能比较大小");
        }
        ResBean res = ResBean.get(resId);
        List<ResBean> children = res.descents(3);
        ResBean ret = null;
        Float max = null;
        for (ResBean child : children) {
            if (isContainProp(child.res().getId(), propId)) {
                Float propV = getFloatProp(child.res().getId(), propId);
                if (ret == null || max == null) {
                    ret = child;
                    max = getFloatProp(child.res().getId(), propId);
                    continue;
                }
                if (propV != null && propV > max) {
                    ret = child;
                    max = propV;
                }

            }
        }
        return ret.res();
    }

    /**
     * 
     * @param resId
     * @param propId
     * @return
     * @throws Exception
     */
    public static ResBean[] topN(Long resId, final Long propId, Integer n) throws Exception {
        PropertyBean propBean = PropertyBean.get(propId);
        if (propBean.property().getDataTypeId().intValue() != DataTypeConstants.DATA_TYPE_NUM) {
            throw new Exception("porpId=[" + propId + "] 不是数字类型，不能比较大小");
        }
        ResBean res = ResBean.get(resId);
        List<ResBean> allChilds = res.descents(3);
        List<ResBean> children = new ArrayList<ResBean>();
        for (ResBean resBean : allChilds) {
            if (isContainProp(resBean.res().getId(), propId)) {
                children.add(resBean);
            }
        }
        Collections.sort(children, new Comparator<ResBean>() {
            @Override
            public int compare(ResBean o1, ResBean o2) {
                Float p1 = getFloatProp(o1.res().getId(), propId);
                Float p2 = getFloatProp(o2.res().getId(), propId);
                if (p1 > p2) {
                    return -1;
                } else if (p1 < p2) {
                    return 1;
                }
                return 0;
            }
        });
        if (children.size() > n) {
            List<ResBean> topNList = children.subList(0, n);
            return topNList.toArray(new ResBean[topNList.size()]);
        }
        return children.toArray(new ResBean[children.size()]);
    }

    private static Float getFloatProp(Long resId, Long propId) {
        Object propVal = getPropertyValue(resId, propId);
        if (propVal != null) {
            return Float.parseFloat(propVal.toString());
        } else {
            return null;
        }
    }

    public static Res minChild(Long resId, Long propId) throws Exception {
        PropertyBean propBean = PropertyBean.get(propId);
        if (propBean.property().getDataTypeId() != DataTypeConstants.DATA_TYPE_NUM) {
            throw new Exception("porpId=[" + propId + "] 不是数字类型，不能比较大小");
        }
        ResBean res = ResBean.get(resId);
        List<ResBean> children = res.descents(3);
        ResBean ret = null;
        Float min = null;
        for (ResBean child : children) {
            if (isContainProp(child.res().getId(), propId)) {
                Float propV = getFloatProp(child.res().getId(), propId);
                if (ret == null || min == null) {
                    ret = child;
                    min = getFloatProp(child.res().getId(), propId);
                    continue;
                }
                if (propV != null && propV < min) {
                    ret = child;
                    min = propV;
                }
            }

        }
        return ret.res();
    }

    /**
     * 获取一个资源一个指标的实时值 使用方法:prop(int,int)
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object getPropertyValue(Long resId, Long propId) {
        String result = propertyValueCache.getValue(resId, propId);
        Property property = PropertyBean.get(propId).property();
        int dataTypeId = property.getDataTypeId().intValue();
        if (result == null) {
            switch (dataTypeId) {
                case DataTypeConstants.DATA_TYPE_STRING:
                    return "";
                case DataTypeConstants.DATA_TYPE_NUM:
                    return 0;
                case DataTypeConstants.DATA_TYPE_DATE:
                    return 0;
                case DataTypeConstants.DATA_TYPE_OBJECT:// 表格类型数据
                    return null;
                case DataTypeConstants.DATA_TYPE_BOOLEAN:
                    return false;
                default:
                    return null;
            }
        }
        switch (dataTypeId) {
            case DataTypeConstants.DATA_TYPE_STRING:
                return result;
            case DataTypeConstants.DATA_TYPE_NUM:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    DecimalFormat numFormat = new DecimalFormat(property.getFormat());
                    // number format 之后再 Long 或 Double 转换一下
                    if ("#".equals(property.getFormat())) {
                        return Long.parseLong(numFormat.format(Double.parseDouble(result)));
                    }
                    return Double.parseDouble(numFormat.format(Double.parseDouble(result)));
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_DATE:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(property.getFormat());
                    try {
                        return simpleDateFormat.parse(result);
                    } catch (ParseException e) {
                        logger.error("format date error", e);
                    }
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_OBJECT:// 表格类型数据
                return result;
            case DataTypeConstants.DATA_TYPE_BOOLEAN:
                if (DataTypeConstants.BOOLEAN_VALUE_TRUE.equals(result)) {
                    return true;
                } else {
                    return false;
                }
            default:
                return result;
        }
    }

    /**
     * 获取表格指标的某一条记录
     * 
     * @param resId   资源ID
     * @param propId  指标ID
     * @param keyCol  列名
     * @param lineNumber  第几行，从0开始
     * @param dataType    列数据类型
     * @return
     */
    public static Object getTablePropertyValue(Long resId, Long propId, String keyCol, int lineNumber) {
        Property property = PropertyBean.get(propId).property();
        int dataTypeId = property.getDataTypeId().intValue();
        if (dataTypeId != DataTypeConstants.DATA_TYPE_OBJECT) {
            return null;
        }
        String result = propertyValueCache.getValue(resId, propId);
        if (result == null) {
            return null;
        }
        int objectKeyCol = getObjectCol(property, keyCol);
        int objectCol = lineNumber;
        String[] values = result.split(SeparatorConstants.LIN_SEPARATOR);

        String[] dataArray = values[objectCol].split(SeparatorConstants.COL_SEPARATOR);
        String objectId = "";
        if (objectKeyCol < dataArray.length) {
            objectId = dataArray[objectKeyCol];
        }
        try {
            if (objectId.matches("\\d+(\\.\\d+)?")) {
                return new Double(objectId);
            } else {
                return objectId;
            }
        } catch (Exception e) {
            return objectId;
        }

    }

    /**
     * 获取表格值列顺序号
     * 
     * @param property
     * @param keyCol
     * @return
     */
    private static int getObjectCol(Property property, String keyCol) {
        String format = property.getFormat();
        String[] formatArray = format.split("[|]");
        for (int r = 0; r < formatArray.length; r++) {
            String colValue = formatArray[r];
            if (keyCol.equals(colValue)) {
                return r;
            }
        }
        return -1;
    }

    /**
     * 获取指标名称
     */
    public static String getPropertyName(Long propId) {
        PropertyBean p = PropertyBean.get(propId);
        return p == null ? "<>" : "<" + p.property().getName() + ">";
    }

    /**
     * 获取一个资源的一个属性值 使用方法:attr(int,int)
     * 
     * @param resId
     * @param attrId
     * @return
     */
    public static Object getAttributeValue(Long resId, Long attrId) {
        ResBean res = ResBean.get(resId);
        AttributeBean attr = AttributeBean.get(attrId);
        Attribute attribute = attr.attribute();
        int dataTypeId = attribute.getDataTypeId().intValue();
        if (res == null || attr == null) {
            switch (dataTypeId) {
                case DataTypeConstants.DATA_TYPE_STRING:
                    return "";
                case DataTypeConstants.DATA_TYPE_NUM:
                    return 0;
                case DataTypeConstants.DATA_TYPE_DATE:
                    return 0;
                case DataTypeConstants.DATA_TYPE_OBJECT:// 表格类型数据
                    return null;
                default:
                    return null;
            }
        }
        ResAttrVal resAttrVal = res.resAttrVal(attrId);
        if (resAttrVal == null) {
            return null;
        }
        String result = resAttrVal.getAttrValue();
        // 按数据类型转换数据
        switch (dataTypeId) {
            case DataTypeConstants.DATA_TYPE_STRING:
                return result;
            case DataTypeConstants.DATA_TYPE_NUM:
                if (attribute.getFormat() != null && !"".equals(attribute.getFormat())) {
                    DecimalFormat numFormat = new DecimalFormat(attribute.getFormat());
                    // number format 之后再 Long 或 Double 转换一下
                    if ("#".equals(attribute.getFormat())) {
                        return Long.parseLong(numFormat.format(Double.parseDouble(result)));
                    }
                    return Double.parseDouble(numFormat.format(Double.parseDouble(result)));
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_DATE:
                if (attribute.getFormat() != null && !"".equals(attribute.getFormat())) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(attribute.getFormat());
                    try {
                        return simpleDateFormat.parse(result);
                    } catch (ParseException e) {
                        logger.error("format date error", e);
                    }
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_OBJECT:
                return Boolean.parseBoolean(result);// 对象类型数据
            default:
                return result;
        }
    }

    /**
     * 获取父资源的ID，使用方法:parent(int)
     * 
     * @param resId
     * @return
     */
    public static Object parent(Long resId) {
        List<ResBean> parents = RelationHelper.parents(resId);
        return parents.get(0).res().getId();
    }

    /**
     * 获取资源名称 使用方法:resname(int)
     * 
     * @param resId
     * @return
     */
    public static String getResName(Long resId) {
        ResBean res = ResBean.get(resId);
        return res == null ? null : res.res().getName();
    }

    /**
     * 获取资源IP地址 使用方法:ip(int)
     * 
     * @param resId
     * @return
     */
    public static String getResIp(Long resId) {
        ResBean res = ResBean.get(resId);
        return res == null ? null : res.res().getIp();
    }

    /**
     * 获取某个指标的每秒增长率 使用方法:inc(int,int,long)
     * 
     * 
     * @param resId
     * @param propId
     * @param time
     * @return
     */
    public static Double inc(Long resId, Long propId, Long time) {
        PropValueBean currentElement = propertyValueCache.getValueBean(resId, propId);
        PropValueBean historyElement = propertyValueCache.getHistoryValue(resId, propId, time);
        int dataTypeId = PropertyBean.get(propId).property().getDataTypeId().intValue();
        if (DataTypeConstants.DATA_TYPE_NUM != dataTypeId) {
            return 0d;
        }
        if (currentElement == null || historyElement == null) {
            return 0d;
        }
        long timeLen = currentElement.getTime().getTime() - historyElement.getTime().getTime();
        if (timeLen <= 0) {
            return 0d;
        }
        double d1 = Double.parseDouble(currentElement.getValue());
        double d2 = Double.parseDouble(historyElement.getValue());
        return ((d1 - d2) / d2) * time / (timeLen / 1000);
    }

    /**
     * 获取上一次的历史值
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object lastPropValue(Long resId, Long propId) {
        PropValueBean historyElement = propertyValueCache.getPreviousValue(resId, propId);
        Property property = PropertyBean.get(propId).property();
        int dataTypeId = PropertyBean.get(propId).property().getDataTypeId().intValue();
        if (null == historyElement) {
            switch (dataTypeId) {
                case DataTypeConstants.DATA_TYPE_STRING:
                    return "";
                case DataTypeConstants.DATA_TYPE_NUM:
                    return 0;
                case DataTypeConstants.DATA_TYPE_DATE:
                    return 0;
                case DataTypeConstants.DATA_TYPE_OBJECT:// 表格类型数据
                    return null;
                default:
                    return null;
            }
        }
        String result = historyElement.getValue();
        switch (dataTypeId) {
            case DataTypeConstants.DATA_TYPE_STRING:
                return result;
            case DataTypeConstants.DATA_TYPE_NUM:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    DecimalFormat numFormat = new DecimalFormat(property.getFormat());
                    if ("#".equals(property.getFormat())) {
                        return Long.parseLong(numFormat.format(Double.parseDouble(result)));
                    }
                    return Double.parseDouble(numFormat.format(Double.parseDouble(result)));
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_DATE:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(property.getFormat());
                    try {
                        return simpleDateFormat.parse(result);
                    } catch (ParseException e) {
                        logger.error("format date error", e);
                    }
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_OBJECT:
                return result;// Table 型数据
            case DataTypeConstants.DATA_TYPE_BOOLEAN:
                if (DataTypeConstants.BOOLEAN_VALUE_TRUE.equals(result)) {
                    return true;
                } else {
                    return false;
                }
            default:
                return result;
        }
    }

    /**
     * 省略小数位 使用方法:round(double)
     * 
     * @param d
     * @return
     */
    public static Long round(Object d) {
        if (d == null)
            return null;
        return Math.round((Double) d);
    }

    /**
     * 省略小数后几位 使用方法:round(double,int)
     * 
     * @param d
     * @param w
     * @return
     */
    public static Double round(Object d, int w) {
        String pattern = "0.";
        for (int i = 0; i < w; i++) {
            pattern += "0";
        }
        if (d == null)
            return null;
        return Double.parseDouble(new java.text.DecimalFormat(pattern).format(d));
    }

    /**
     * 包装boolean类型数据,返回是否
     * 
     * @param b
     * @return
     */
    public static String booleanMsg(boolean b) {
        if (b) {
            return "是";
        }
        return "否";
    }

    /**
     * 获取指标的实时值，根据不同的数据类型返回不同的虚拟值
     * 
     * @param resId
     * @param propId
     * @return
     */
    public static Object testGetPropertyValue(Long resId, Long propId) {
        String result = "1";
        Property property = PropertyBean.get(propId).property();
        int dataTypeId = property.getDataTypeId().intValue();
        switch (dataTypeId) {
            case DataTypeConstants.DATA_TYPE_STRING:
                return result;
            case DataTypeConstants.DATA_TYPE_NUM:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    DecimalFormat numFormat = new DecimalFormat(property.getFormat());
                    // number format 之后再 Long 或 Double 转换一下
                    if ("#".equals(property.getFormat())) {
                        return Long.parseLong(numFormat.format(Double.parseDouble(result)));
                    }
                    return Double.parseDouble(numFormat.format(Double.parseDouble(result)));
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_DATE:
                if (property.getFormat() != null && !"".equals(property.getFormat())) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(property.getFormat());
                    try {
                        return simpleDateFormat.parse(result);
                    } catch (ParseException e) {
                        logger.error("format date error", e);
                    }
                }
                return Double.parseDouble(result);
            case DataTypeConstants.DATA_TYPE_OBJECT:
                return result;// Table 型数据
            case DataTypeConstants.DATA_TYPE_BOOLEAN:
                if (DataTypeConstants.BOOLEAN_VALUE_TRUE.equals(result)) {
                    return true;
                } else {
                    return false;
                }
            default:
                return result;
        }
    }

    /**
     * 
     * 获得所有具有指定指标值的资源
     * @param resId
     * @param propId
     * @param value
     * @return 
     *List<Res>
     * @exception 
     * @since  1.0.0
     */
    public static List<Res> specialChild(Long resId, Long propId, String value) {
        List<Res> ret = new ArrayList<Res>();
        List<Res> propChild = childByProp(resId, propId);
        for (Res res : propChild) {
            String pv = getPropertyValue(res.getId(), propId).toString();
            if (pv.equalsIgnoreCase(value)) {
                ret.add(res);
            }
        }
        return ret;
    }

    public static void main(String[] args) throws InterruptedException {
        // System.out.println(round(553311.126213214, 1));
        DecimalFormat numFormat = new DecimalFormat("#");
        System.out.println(numFormat.format(Double.parseDouble(0 + "")));
    }

    /**
     * 将一个字符串类型的值转换成数字类型
     * @param value
     * @return
     */
    public static double toInt(String value) {
        if (value != null && value.trim().matches("\\d+(.\\d*)?")) {
            return Double.parseDouble(value.trim());
        }
        return -1;
    }

}